package com.glwan.fixedassetapp.helper;

import static android.content.Context.MODE_PRIVATE;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;

import androidx.annotation.NonNull;

import com.glwan.fixedassetapp.R;
import com.glwan.fixedassetapp.handler.ReaderResponseInterfaces;
import com.glwan.fixedassetapp.model.RFIDTagData;
import com.glwan.fixedassetapp.utils.CommonUtil;
import com.handheld.uhfr.UHFRManager;
import com.uhf.api.cls.Reader;

import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;

import cn.pda.serialport.Tools;

public class AlpsReaderHelper implements RFIDDeviceInterface {

    private static final String TAG = "Alps";
    public static UHFRManager mUhfrManager;
    public static boolean connectStatus = false;
    public static SharedPreferences mSharedPreferences;
    private static AlpsReaderHelper alpsReaderHelper;
    private final int MSG_INVENTORY = 1;
    private final int MSG_INVENTORY_TIME = 1001;
    SharedUtil sharedUtil;
    //0--inventory 1--locate
    private int inventoryMode = 0;
    //tagPattern
    private String tagPattern;
    private Timer timer;
    private long lastCount = 0;//
    private long speed = 0;

    private Map<String, TagInfo> tagInfoMap = new LinkedHashMap<>();//
//    private List<TagInfo> tagInfoList = new ArrayList<TagInfo>();//
//    public List<String> listEPC = new ArrayList<>();//epc数据

    private boolean isReader = false;

    private Handler soundHandler;
    private Runnable soundTask = null;

    private boolean isConnectUHF = false;

    private Activity activity;
    private Handler handler;

    private AlpsReaderHelper() {
    }

    public static AlpsReaderHelper getInstance(Activity activity) {
        if (alpsReaderHelper == null) {
            alpsReaderHelper = new AlpsReaderHelper();
        }
        alpsReaderHelper.activity = activity;
        return alpsReaderHelper;
    }

    /**
     * 连接uhf模块
     */
    @Override
    public boolean connect() {
        isConnectUHF = false;
        //init sound
        UtilSound.initSoundPool(activity);

        soundHandler = new Handler();

        handler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
            }
        };

        // Init Uhf module
        mUhfrManager = UHFRManager.getInstance();

        mSharedPreferences = activity.getSharedPreferences("UHF", MODE_PRIVATE);

        if (mUhfrManager != null) {
            //5106和6106 /6107和6108 支持33db
            sharedUtil = new SharedUtil(activity);
            Reader.READER_ERR err = mUhfrManager.setPower(sharedUtil.getPower(), sharedUtil.getPower());//set uhf module power

            if (err == Reader.READER_ERR.MT_OK_ERR) {
                isConnectUHF = true;
                Reader.READER_ERR err1 = mUhfrManager.setRegion(Reader.Region_Conf.valueOf(sharedUtil.getWorkFreq()));

                CommonUtil.toastShow(activity, "FreRegion:" + Reader.Region_Conf.valueOf(sharedUtil.getWorkFreq()) +
                        "\n" + "Read Power:" + sharedUtil.getPower() +
                        "\n" + "Write Power:" + sharedUtil.getPower(), CommonUtil.SUCCESS, true);

                setParam();
//                if(mUhfrManager.getHardware().equals("1.1.01")){
//                    type=0;
//                }

            } else {
                //5101 30db
                Reader.READER_ERR err1 = mUhfrManager.setPower(30, 30);//set uhf module power
                if (err1 == Reader.READER_ERR.MT_OK_ERR) {
                    isConnectUHF = true;
                    mUhfrManager.setRegion(Reader.Region_Conf.valueOf(mSharedPreferences.getInt("freRegion", 1)));
                    CommonUtil.toastShow(activity, "FreRegion:" + Reader.Region_Conf.valueOf(mSharedPreferences.getInt("freRegion", 1)) +
                            "\n" + "Read Power:" + 30 +
                            "\n" + "Write Power:" + 30, CommonUtil.SUCCESS, true);
                    setParam();
                } else {
                    CommonUtil.toastShow(activity, activity.getString(R.string.connectFail), CommonUtil.ERROR, true);
                }
            }

        } else {
            CommonUtil.toastShow(activity, activity.getString(R.string.connectFail), CommonUtil.ERROR, true);
        }


        return isConnectUHF;
    }

    /**
     * 断开设备连接
     *
     * @return
     */
    @Override
    public boolean disconnect() {
        if (mUhfrManager != null) {//close uhf module
            isConnectUHF = mUhfrManager.close();
            mUhfrManager = null;
        }
        return !isConnectUHF;
    }

    /**
     * 开始盘点
     *
     * @return
     */
    @Override
    public boolean startInventory() {

        //开启多标签
        if (inventoryMode == 0) {
            speed = 0;//
            isReader = mUhfrManager.asyncStartReading() == Reader.READER_ERR.MT_OK_ERR;

        } else {
            isReader = true;
        }

        if (!isReader) {
            stopInventory();
            isReader = false;
            return isReader;
        }
        handler.postDelayed(inventoryThread, 0);

        return isReader;
    }

    /**
     * 停止盘点
     *
     * @return
     */
    @Override
    public boolean stopInventory() {
        if (isConnectUHF) {
            if (isReader) {
                if (inventoryMode == 0) {
                    mUhfrManager.asyncStopReading();
                }
                handler.removeCallbacks(inventoryThread);
                soundHandler.removeCallbacks(soundTask);
                isReader = false;
                if (timer != null) {
                    timer.cancel();
                    timer = null;
                }

            }
        }
        mUhfrManager.setCancleInventoryFilter();
        return isReader;
    }    /**
     * 盘点线程类
     */
    private Runnable inventoryThread = new Runnable() {
        @Override
        public void run() {
            Log.e(TAG, "inventoryThread is running");
            List<Reader.TAGINFO> listTag = null;
            //6C
            //
            if (inventoryMode == 1) {
                isReader = mUhfrManager.setInventoryFilter(Tools.HexString2Bytes(tagPattern), 1, 2, true);

                listTag = mUhfrManager.tagInventoryByTimer((short) 50);
            } else {
                listTag = mUhfrManager.tagInventoryRealTime();

            }
//            else{
//                if (checkBoxTid.isChecked()) {
//                    //
//                    listTag = mUhfrManager.tagEpcTidInventoryByTimer((short) 50) ;
//                }else{
//                    listTag = mUhfrManager.tagInventoryByTimer((short) 50); ;
//                }
//            }
            if (listTag == null) {
                Log.e(TAG, "listTag = null");
                //
                if (inventoryMode == 0) {
                    mUhfrManager.asyncStopReading();
                    mUhfrManager.asyncStartReading();
                }
            }
            //
            if (listTag != null && !listTag.isEmpty()) {
                Log.e(TAG, "inventory listTag size = " + listTag.size());
                for (Reader.TAGINFO taginfo : listTag) {


//                    Map<String, TagInfo> infoMap = pooled6cData(taginfo);

//                    tagInfoList.clear();
//                    tagInfoList.addAll(infoMap.values());
//                    //
//                    listEPC.clear();
//                    listEPC.addAll(infoMap.keySet());

                    int rssi = taginfo.RSSI;
                    String epc = Tools.Bytes2HexString(taginfo.EpcId, taginfo.EpcId.length);
                    RFIDTagData rfidTagData = new RFIDTagData();
                    rfidTagData.setRssi(taginfo.RSSI);
                    rfidTagData.setEpc(epc);
                    rfidTagData.setAntennaID(taginfo.AntennaID);
                    Log.w("epc", epc);

                    if (inventoryMode == 1) {
                        Log.w("tagPattern - epc", epc);
                        Log.w("tagPattern - rssi", String.valueOf(rssi));
                        if (tagPattern.equals(epc)) {
                            UtilSound.play(1, 0);
                            if (rssi >= -25) {
                                rfidTagData.setRelativeDistance((short) 100);
                            } else if (rssi >= -75) {
                                rfidTagData.setRelativeDistance((short) (100 - (Math.abs((double) (rssi - -25) / (double) (-75 - -25)) * 100)));
                            }
                        } else {
                            rfidTagData.setRelativeDistance((short) (0));
                        }
                    } else {
                        UtilSound.play(1, 0);
//                        sendData(rfidTagData);
                    }
                    sendData(rfidTagData);


                }
//                epcListViewAdapter.notifyDataSetChanged();
//                handler.sendEmptyMessage(MSG_INVENTORY);

            } else {
                //
                speed = 0;
            }
            //
//            if (checkBoxLoop.isChecked()) {
            handler.postDelayed(inventoryThread, 0);
//            }else{
//                if(timer != null){
//                    timer.cancel();
//                    timer = null ;
//                }
//                handler.sendEmptyMessage(MSG_INVENROTY_TIME);
//                isReader = false ;
//            }

        }
    };

    private void sendData(RFIDTagData rfidTagData) {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {

                activity.runOnUiThread(() -> {
                    if (activity instanceof
                            ReaderResponseInterfaces.ResponseTagHandler) {
                        ((ReaderResponseInterfaces.ResponseTagHandler) activity).handleResponse(rfidTagData);
//                                editText.append(stringBuilder.toString());
                    }
                });
                return null;
            }
        }.execute();
    }


    /**
     * 设置功率5-30
     *
     * @param power 功率大小
     * @return boolean
     */
    @Override
    public boolean setPower(int power) {

        return Reader.READER_ERR.MT_OK_ERR == mUhfrManager.setPower(power, power);

    }

    /**
     * 返回读写功率
     *
     * @return 功率
     */
    @Override
    public Integer getPower() {

        int power = 0;
        int[] powerArray = mUhfrManager.getPower();
        if (powerArray != null && powerArray.length > 0) {
            power = powerArray[0];
        }
        return power;
    }

    @Override
    public boolean setSession(int session) {
        return mUhfrManager.setGen2session(session);
    }

    @Override
    public Integer getSession() {
        return mUhfrManager.getGen2session();
    }

    @Override
    public boolean isConnected() {
        return isConnectUHF;
    }

    @Override
    public void changeInventoryMode(int mode, String tagPattern) {
        Log.i(TAG, "MODE:" + mode + ", TAG_PATTERN" + tagPattern);
        this.inventoryMode = mode;
        this.tagPattern = tagPattern;
    }

    private void setParam() {
        //session
        mUhfrManager.setGen2session(sharedUtil.getSession());
        //taget
        mUhfrManager.setTarget(sharedUtil.getTarget());
        //q value
        mUhfrManager.setQvaule(sharedUtil.getQvalue());
    }

    /**
     * 循环处理6c标签数据
     *
     * @param info
     * @return
     */
    public Map<String, TagInfo> pooled6cData(Reader.TAGINFO info) {

        String epcAndTid = Tools.Bytes2HexString(info.EpcId, info.EpcId.length);

        Log.i(TAG, epcAndTid);
        if (tagInfoMap.containsKey(epcAndTid)) {
            TagInfo tagInfo = tagInfoMap.get(epcAndTid);
            Long count = tagInfo.getCount();
            count++;
            tagInfo.setRssi(info.RSSI + "");
            tagInfo.setCount(count);
            if (info.EmbededData != null && info.EmbededDatalen > 0) {
                tagInfo.setTid(Tools.Bytes2HexString(info.EmbededData, info.EmbededDatalen));
            }
            tagInfoMap.put(epcAndTid, tagInfo);
        } else {
            TagInfo tag = new TagInfo();
//            tag.setIndex(index);
            tag.setType("6C");
            tag.setEpc(Tools.Bytes2HexString(info.EpcId, info.EpcId.length));
            tag.setCount(1l);
//            tag.setIsShowTid(checkBoxTid.isChecked());
            if (info.EmbededData != null && info.EmbededDatalen > 0) {
                tag.setTid(Tools.Bytes2HexString(info.EmbededData, info.EmbededDatalen));
            }
            tag.setRssi(info.RSSI + "");
            Log.e("rssi", info.RSSI + "");
            tagInfoMap.put(epcAndTid, tag);
//            index++;
        }
        return tagInfoMap;
    }

    /**
     * sound task
     */
    private void soundTask() {
        soundTask = new Runnable() {
            @Override
            public void run() {
//                int rateValue = 1 ;
                Log.e(TAG, "rateValue = " + speed);
                if (speed != 0) {
                    UtilSound.play(1, 0);
                }
                soundHandler.postDelayed(this, 40);
            }
        };
        soundHandler.postDelayed(soundTask, 0);
    }

    /**
     * Alps声音处理util类
     */
    static class UtilSound {

        public static SoundPool sp;
        public static Map<Integer, Integer> suondMap;
        public static Context context;
        private static long time = 0;
        private static long currentTime = 0;
        private static long lastTime = SystemClock.elapsedRealtime();

        //init sound pool
        public static void initSoundPool(Context context) {
            UtilSound.context = context;
            sp = new SoundPool(1, AudioManager.STREAM_MUSIC, 100);
            suondMap = new HashMap<Integer, Integer>();
            suondMap.put(1, sp.load(context, R.raw.alps_barcodebeep, 1));
            suondMap.put(2, sp.load(context, R.raw.alps_beep, 1));
            suondMap.put(3, sp.load(context, R.raw.alps_beeps, 1));
        }

        //play sound
        public static void play(int sound, int number) {
            if (System.currentTimeMillis() - time > 30) {
                AudioManager am = (AudioManager) UtilSound.context.getSystemService(UtilSound.context.AUDIO_SERVICE);
                float audioMaxVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
                float audioCurrentVolume = am.getStreamVolume(AudioManager.STREAM_MUSIC);
                float volumnRatio = audioCurrentVolume / audioMaxVolume;

                sp.play(3, 1, 1, 0, 0, 2f);//0.5-2.0 speed
                time = System.currentTimeMillis();
            }

        }

        public static void voiceTips(int type, int size, boolean asyncFlag) {
            if (type == 0 && !asyncFlag) {
                for (int i = 0; i < size; i++) {
                    currentTime = SystemClock.elapsedRealtime();
                    if ((currentTime - lastTime) < 40) {
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        continue;
                    }
                    play(1, 0);
                    lastTime = currentTime;
                }
            } else {
                currentTime = SystemClock.elapsedRealtime();
                long l = currentTime - lastTime;
//            log("voiceTips", "time: " + l);
                if (l < 40) {
                    return;
                }
                play(1, 0);
                lastTime = currentTime;
            }
        }

    }

    class SharedUtil {


        private final SharedPreferences mSharedPreferences;

        public SharedUtil(Context context) {
            mSharedPreferences = context.getSharedPreferences("UHF", Context.MODE_PRIVATE);
        }


        public void saveWorkFreq(int workFreq) {
            SharedPreferences.Editor editor = mSharedPreferences.edit();
            editor.putInt("workFreq", workFreq);
            editor.commit();
        }

        //0 CA  //1 FCC //2EU
        public int getWorkFreq() {
            return mSharedPreferences.getInt("workFreq", 1);
        }


        public void savePower(int power) {
            SharedPreferences.Editor editor = mSharedPreferences.edit();
            editor.putInt("power", power);
            editor.commit();
        }


        public int getPower() {
            return mSharedPreferences.getInt("power", 33);
        }


        public void saveSession(int session) {
            SharedPreferences.Editor editor = mSharedPreferences.edit();
            editor.putInt("session", session);
            editor.commit();
        }


        public int getSession() {
            return mSharedPreferences.getInt("session", 0);
        }


        public void saveQvalue(int qvalue) {
            SharedPreferences.Editor editor = mSharedPreferences.edit();
            editor.putInt("qvalue", qvalue);
            editor.commit();
        }


        public int getQvalue() {
            return mSharedPreferences.getInt("qvalue", 0);
        }


        public void saveTarget(int target) {
            SharedPreferences.Editor editor = mSharedPreferences.edit();
            editor.putInt("target", target);
            editor.commit();
        }


        public int getTarget() {

            return mSharedPreferences.getInt("target", 0);
        }
    }

    /**
     * 标签类
     */
    public class TagInfo implements Serializable {
        private Long index;
        private String type;
        private String epc;
        private Long count;
        private String tid;
        private String rssi;
        private String userData;
        private String reservedData;
        private String nmv2d;
        private String epcData;
        private Integer ltu27;
        private Integer ltu31;
        private String moisture;
        private int ctesius;
        private boolean isShowTid;

        public TagInfo() {
        }

        public TagInfo(Long index, String type, String epc, String tid, String rssi) {
            this.index = index;
            this.type = type;
            this.epc = epc;
            this.tid = tid;
            this.rssi = rssi;
        }

        public Long getIndex() {
            return index;
        }

        public void setIndex(Long index) {
            this.index = index;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getEpc() {
            return epc;
        }

        public void setEpc(String epc) {
            this.epc = epc;
        }

        public Long getCount() {
            return count;
        }

        public void setCount(Long count) {
            this.count = count;
        }

        public String getTid() {
            return tid;
        }

        public void setTid(String tid) {
            this.tid = tid;
        }

        public String getRssi() {
            return rssi;
        }

        public void setRssi(String rssi) {
            this.rssi = rssi;
        }

        public String getUserData() {
            return userData;
        }

        public void setUserData(String userData) {
            this.userData = userData;
        }

        public String getReservedData() {
            return reservedData;
        }

        public void setReservedData(String reservedData) {
            this.reservedData = reservedData;
        }

        public String getNmv2d() {
            return nmv2d;
        }

        public void setNmv2d(String nmv2d) {
            this.nmv2d = nmv2d;
        }

        public String getEpcData() {
            return epcData;
        }

        public void setEpcData(String epcData) {
            this.epcData = epcData;
        }

        public Integer getLtu27() {
            return ltu27;
        }

        public void setLtu27(Integer ltu27) {
            this.ltu27 = ltu27;
        }

        public Integer getLtu31() {
            return ltu31;
        }

        public void setLtu31(Integer ltu31) {
            this.ltu31 = ltu31;
        }

        public String getMoisture() {
            return moisture;
        }

        public void setMoisture(String moisture) {
            this.moisture = moisture;
        }

        public int getCtesius() {
            return ctesius;
        }

        public void setCtesius(int ctesius) {
            this.ctesius = ctesius;
        }

        public boolean getIsShowTid() {
            return isShowTid;
        }

        public void setIsShowTid(boolean isShowTid) {
            this.isShowTid = isShowTid;
        }

        @Override
        public String toString() {
            return "TagInfo{" +
                    "index=" + index +
                    ", type='" + type + '\'' +
                    ", epc='" + epc + '\'' +
                    ", count=" + count +
                    ", tid='" + tid + '\'' +
                    ", rssi='" + rssi + '\'' +
                    ", userData='" + userData + '\'' +
                    ", reservedData='" + reservedData + '\'' +
                    '}';
        }
    }




}
